const fs = require('fs');

class SubtitleService {
  /**
   * Parse SRT subtitle file
   * @param {string} filePath - Path to the SRT file
   * @returns {Promise<Array>} - Promise that resolves with parsed subtitles
   */
  async parseSRT(filePath) {
    try {
      // Check if file exists
      if (!fs.existsSync(filePath)) {
        throw new Error(`Subtitle file not found: ${filePath}`);
      }

      // Read file content
      const content = fs.readFileSync(filePath, 'utf-8');

      // Parse SRT content
      const subtitles = [];
      const blocks = content.split(/\n\s*\n/);

      for (const block of blocks) {
        const lines = block.trim().split('\n');
        if (lines.length >= 3) {
          const index = lines[0];
          const timeLine = lines[1];
          const textLines = lines.slice(2);

          // Parse time format: 00:00:00,000 --> 00:00:05,000
          const timeMatch = timeLine.match(/(\d{2}:\d{2}:\d{2}),(\d{3})\s-->\s(\d{2}:\d{2}:\d{2}),(\d{3})/);
          if (timeMatch) {
            const startTime = this.parseTime(timeMatch[1], timeMatch[2]);
            const endTime = this.parseTime(timeMatch[3], timeMatch[4]);

            subtitles.push({
              index: parseInt(index),
              start: startTime,
              end: endTime,
              text: textLines.join('\n'),
            });
          }
        }
      }

      return subtitles;
    } catch (error) {
      throw new Error(`Failed to parse SRT file: ${error.message}`);
    }
  }

  /**
   * Parse ASS subtitle file
   * @param {string} filePath - Path to the ASS file
   * @returns {Promise<Array>} - Promise that resolves with parsed subtitles
   */
  async parseASS(filePath) {
    try {
      // Check if file exists
      if (!fs.existsSync(filePath)) {
        throw new Error(`Subtitle file not found: ${filePath}`);
      }

      // Read file content
      const content = fs.readFileSync(filePath, 'utf-8');

      // Parse ASS content
      const subtitles = [];
      const lines = content.split('\n');

      let isEventSection = false;
      for (const line of lines) {
        const trimmedLine = line.trim();

        // Check for Events section
        if (trimmedLine === '[Events]') {
          isEventSection = true;
          continue;
        }

        // Stop parsing if we reach another section
        if (trimmedLine.startsWith('[') && trimmedLine.endsWith(']')) {
          isEventSection = false;
        }

        // Parse dialogue lines
        if (isEventSection && trimmedLine.startsWith('Dialogue:')) {
          const parts = trimmedLine.split(',');
          if (parts.length >= 10) {
            // Parse time format: 0:00:00.00, 0:00:05.00
            const startTime = this.parseASSTime(parts[1]);
            const endTime = this.parseASSTime(parts[2]);

            // Extract text (everything after the 9th comma)
            const text = parts.slice(9).join(',');

            subtitles.push({
              start: startTime,
              end: endTime,
              text: text,
            });
          }
        }
      }

      return subtitles;
    } catch (error) {
      throw new Error(`Failed to parse ASS file: ${error.message}`);
    }
  }

  /**
   * Parse LRC lyrics file
   * @param {string} filePath - Path to the LRC file
   * @returns {Promise<Array>} - Promise that resolves with parsed lyrics
   */
  async parseLRC(filePath) {
    try {
      // Check if file exists
      if (!fs.existsSync(filePath)) {
        throw new Error(`Lyrics file not found: ${filePath}`);
      }

      // Read file content
      const content = fs.readFileSync(filePath, 'utf-8');

      // Parse LRC content
      const lyrics = [];
      const lines = content.split('\n');

      for (const line of lines) {
        const trimmedLine = line.trim();

        // Parse time format: [00:00.00] Lyrics text
        const timeMatch = trimmedLine.match(/\[(\d{2}):(\d{2})\.(\d{2})\](.*)/);
        if (timeMatch) {
          const minutes = parseInt(timeMatch[1]);
          const seconds = parseInt(timeMatch[2]);
          const centiseconds = parseInt(timeMatch[3]);
          const text = timeMatch[4];

          const time = minutes * 60 + seconds + centiseconds / 100;

          lyrics.push({
            time: time,
            text: text,
          });
        }
      }

      return lyrics;
    } catch (error) {
      throw new Error(`Failed to parse LRC file: ${error.message}`);
    }
  }

  /**
   * Parse time string in format HH:MM:SS to seconds
   * @param {string} timeStr - Time string in HH:MM:SS format
   * @param {string} milliseconds - Milliseconds string
   * @returns {number} - Time in seconds
   */
  parseTime(timeStr, milliseconds) {
    const [hours, minutes, seconds] = timeStr.split(':').map(Number);
    return hours * 3600 + minutes * 60 + seconds + parseInt(milliseconds) / 1000;
  }

  /**
   * Parse ASS time string in format H:MM:SS.cc to seconds
   * @param {string} timeStr - Time string in H:MM:SS.cc format
   * @returns {number} - Time in seconds
   */
  parseASSTime(timeStr) {
    const [hours, minutes, secondsAndCentiseconds] = timeStr.split(':');
    const [seconds, centiseconds] = secondsAndCentiseconds.split('.');
    return parseInt(hours) * 3600 + parseInt(minutes) * 60 + parseInt(seconds) + parseInt(centiseconds) / 100;
  }

  /**
   * Extract words from subtitle text
   * @param {string} text - Subtitle text
   * @returns {Array} - Array of words
   */
  extractWords(text) {
    // Remove HTML tags and special characters
    const cleanText = text.replace(/<[^>]*>/g, '').replace(/[^\w\s]/g, ' ');

    // Split by whitespace and filter out empty strings
    const words = cleanText.split(/\s+/).filter(word => word.length > 0);

    // Convert to lowercase and remove duplicates
    return [...new Set(words.map(word => word.toLowerCase()))];
  }

  /**
   * Find subtitle entry for a given time
   * @param {Array} subtitles - Array of subtitle entries
   * @param {number} time - Time in seconds
   * @returns {Object|null} - Subtitle entry or null if not found
   */
  findSubtitleAtTime(subtitles, time) {
    return subtitles.find(sub => time >= sub.start && time <= sub.end) || null;
  }

  /**
   * Find lyrics entry for a given time
   * @param {Array} lyrics - Array of lyrics entries
   * @param {number} time - Time in seconds
   * @returns {Object|null} - Lyrics entry or null if not found
   */
  findLyricsAtTime(lyrics, time) {
    for (let i = lyrics.length - 1; i >= 0; i--) {
      if (time >= lyrics[i].time) {
        return lyrics[i];
      }
    }
    return null;
  }
}

module.exports = SubtitleService;
